/////precompiled////////
#include "precompiled.h"
////////////////////////


#include "grf_TWindow.h"

#include "prs_Menu.h"

using namespace grf;

// TShift /////////////////////////////////////////////////////////////////////

//
/*
void TShift::operator = (Classes::TShiftState V)
{
  if (V.Contains(ssShift))  { (*this) << Shift;}
  if (V.Contains(ssAlt))    { (*this) << Alt;}
  if (V.Contains(ssCtrl))   { (*this) << Ctrl;}
  if (V.Contains(ssLeft))   { (*this) << Left;}
  if (V.Contains(ssRight))  { (*this) << Right;}
  if (V.Contains(ssMiddle)) { (*this) << Middle;}
  if (V.Contains(ssDouble)) { (*this) << Double;}
}
*/

// TPaint /////////////////////////////////////////////////////////////////////

//
TPaint::TPaint(TWindow &Window) : DC(Window)/*,Graphics(DC)*/ 
{
}

// TWindowArray ///////////////////////////////////////////////////////////////

// TWindow ////////////////////////////////////////////////////////////////////

//
TWindow::TWindow()  //TWindow *Parent,bool EnDelete) : svl::TNode<TWindow>(children,Parent,EnDelete)
{
  mouseIsEntered = false;

  //SetWindowLong(GWL_STYLE,WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX);
  //SetWindowLong(GWL_EXSTYLE,WS_EX_TOOLWINDOW);
}                                         

//
TWindow::~TWindow()
{
  //svl::TNode<TWindow>::~TNode();
  //DestroyWindow();
}

/***********************************
//
int TWindow::ShowMain()
{
  isMain = true; ::SetWindowLong(Handle(),GWL_EXSTYLE,WS_EX_APPWINDOW);
  
  ::ShowWindow(Handle(),SW_SHOW); MSG msg = { 0 }; while (::GetMessage(&msg, NULL, 0, 0)) 
	{
    //if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
  	
	  ::TranslateMessage(&msg); 
	  ::DispatchMessage (&msg);
  }
  return (int) msg.wParam;
}

//
void TWindow::Show()
{
  ::ShowWindow(Handle(),SW_SHOW);
}

//
void TWindow::Hide()
{
  ::ShowWindow(Handle(),SW_HIDE);
}
******************************************/

//
TPoint TWindow::ClientToScreen(TPoint PtClient)
{
  POINT Pt; Pt.x = PtClient.X; Pt.y = PtClient.Y;
  ::ClientToScreen(*this,&Pt); return Pt;
}

//
TPoint TWindow::ScreenToClient(TPoint PtScreen)
{
  POINT Pt; Pt.x = PtScreen.X; Pt.y = PtScreen.Y;
  ::ScreenToClient(*this,&Pt); return Pt;
}

//
void TWindow::MoveWindow(TRect Rect,bool Repaint)
{
  ::MoveWindow(*this,Rect.Left,Rect.Top,Rect.Width,Rect.Height,Repaint);
}

//
void TWindow::MoveWindow(int L,int T,int W,int H,bool Repaint)
{
  ::MoveWindow(*this,L,T,W,H,Repaint);
}

//
void TWindow::MoveWindowAroundClientRectTB(
  TSize ClientSizeThis,
  TWindow &WinFrom,
  TRect RClientFrom,
  bool RepaintThis
){
  TRect Rw = WinFrom.GetWindowRect();
  TRect Rc = WinFrom.GetClientRect();
    
  TRect RWindow; 
    RWindow.SetLeftTop(WinFrom.ClientToScreen(RClientFrom.LeftBottom()));
    RWindow.Width  = ClientSizeThis.Width  + (Rw.Width -Rc.Width );
    RWindow.Height = ClientSizeThis.Height + (Rw.Height-Rc.Height);

  RECT R; ::SystemParametersInfo(SPI_GETWORKAREA,0,&R,0);
  TRect RWorkArea(R);
  
  if (RWindow.Right() > RWorkArea.Right()) { 
    RWindow.Left -= RWindow.Right() - RWorkArea.Right();
  }
  else if (RWindow.Left < RWorkArea.Left) { 
    RWindow.Left = RWorkArea.Left;
  }
  RWindow.SetRight( min(RWindow.Right(),RWorkArea.Right()) );

  if (RWindow.Bottom() > RWorkArea.Bottom()) { 
    RWindow.Top = WinFrom.ClientToScreen(RClientFrom.LeftTop()).Y - RWindow.Height;
  }
  //else if (RWindow.Top < RWorkArea.Top) { 
    //RWindow.Top = RWorkArea.Top;
  //}
  RWindow.Top = max(RWindow.Top,RWorkArea.Top);

/***********
  if (RWindow.Top - RWorkArea.Top > RWorkArea.Bottom() - RWindow.Top) {
    int Bottom = RWindow.Top - RClientFrom.Height;
    RWindow.Top = RWorkArea.Top; RWindow.SetBottom(Bottom); 
  }
  else { 
    RWindow.SetBottom( min(RWindow.Bottom(),RWorkArea.Bottom()) ); 
  }
***********/
  MoveWindow(RWindow,RepaintThis);
}

//
void TWindow::InvalidateRect(TRect Rect,bool BkErase)
{
  //Rect.MMtoPT(GetScale());
  ::InvalidateRect(*this,&(::RECT)Rect,BkErase);
}

//
void TWindow::InvalidateRect(bool BkErase)
{
  ::InvalidateRect(*this,NULL,BkErase);
}

//
LRESULT TWindow::TWindow_WndProc(TMessage &Message)
{
  static const int SHIFTED = 0x8000;

  switch (Message.Msg)
  {
    case WM_SETFOCUS:
    {
      TWindow_FocusEnter();
      //bHandled = true;
      return 0;
    }
    break;

    case WM_KILLFOCUS:
    {
      TWindow_FocusExit();
      //bHandled = true;
      return 0;
    }
    break;

    case WM_CHAR:
    {
      TKeyboardChar Param;
      Param.Key = Message.WParam;
      TWindow_KeyboardChar(Param);
      //bHandled = true;
      return 0;
    }
    break;

    case WM_MOUSEMOVE:
    {
      if (!mouseIsEntered) 
      {
        TRACKMOUSEEVENT me = { 0 };
        me.cbSize    = sizeof(TRACKMOUSEEVENT);
        me.dwFlags   = TME_LEAVE;//|TME_NONCLIENT;
        me.hwndTrack = Handle();

        mouseIsEntered = true;
        ::TrackMouseEvent(&me);                
        TWindow_MouseEnter();
      }
                    
      TMouse Mouse;
      Mouse.State = TMouse::EState_Move;

      if (Message.WParam & MK_CONTROL)
          Mouse.Shift << TShift::Ctrl;
      if (Message.WParam & MK_SHIFT)
          Mouse.Shift << TShift::Shift;
      if (Message.WParam & MK_LBUTTON)
          Mouse.Shift << TShift::Left;
      if (Message.WParam & MK_RBUTTON)
          Mouse.Shift << TShift::Right;
      if (Message.WParam & MK_MBUTTON)
          Mouse.Shift << TShift::Middle;

      Mouse.PtClient = MAKEPOINTS(Message.LParam);
      //Mouse.PtClient.PTtoMM(GetScale());

      //Mouse.PtClient.X = GET_X_LPARAM(Message.LParam); 
      //Mouse.PtClient.Y = GET_Y_LPARAM(Message.LParam); 

      TWindow_Mouse(Mouse);
      //bHandled = true;
      return 0;
    }
    break;

    case WM_MOUSEWHEEL:
    {
      TMouseWheel Param;
      Param.Delta = GET_WHEEL_DELTA_WPARAM(Message.WParam);
      Param.PtClient = ScreenToClient(MAKEPOINTS(Message.LParam));
      //Param.PtClient.PTtoMM(GetScale());

      if (Message.WParam & MK_CONTROL)
          Param.Shift << TShift::Ctrl;
      if (Message.WParam & MK_SHIFT)
          Param.Shift << TShift::Shift;
      if (Message.WParam & MK_LBUTTON)
          Param.Shift << TShift::Left;
      if (Message.WParam & MK_RBUTTON)
          Param.Shift << TShift::Right;
      if (Message.WParam & MK_MBUTTON)
          Param.Shift << TShift::Middle;

      TWindow_MouseWheel(Param);
    }
    break;

    case WM_MOUSELEAVE:
    {
      mouseIsEntered = false;
      TWindow_MouseExit();
    }
    break;

/***********
    case WM_SYSKEYDOWN:
    {
    ::MessageBeep(0);
    }
    break;
*************/    
    
    case WM_KEYDOWN:
    {
      TKeyboardKey Param;
      Param.State = TKeyboardKey::EState_Down;

      if (GetKeyState(VK_SHIFT) & SHIFTED) 
          Param.Shift << TShift::Shift;
      if (GetKeyState(VK_CONTROL) & SHIFTED) 
          Param.Shift << TShift::Ctrl;
      if (GetKeyState(VK_MENU) & SHIFTED) 
          Param.Shift << TShift::Alt;

      Param.Key = Message.WParam;
      TWindow_KeyboardKey(Param);
      //bHandled = true;
      return 0;
    }
    break;

    case WM_KEYUP:
    {
      TKeyboardKey Param;
      Param.State = TKeyboardKey::EState_Up;

      if (GetKeyState(VK_SHIFT) & SHIFTED) 
          Param.Shift << TShift::Shift;
      if (GetKeyState(VK_CONTROL) & SHIFTED) 
          Param.Shift << TShift::Ctrl;
      if (GetKeyState(VK_MENU) & SHIFTED) 
          Param.Shift << TShift::Alt;

      Param.Key = Message.WParam;
      TWindow_KeyboardKey(Param);
      //bHandled = true;
      return 0;
    }
    break;              
    
    case WM_SHOWWINDOW:
    {
      svl::TWindow::TWindow_WndProc(Message);
      TWindow_ShowWindow(Message.WParam != 0);
      //bHandled = true;
      return 0;
    }             
    break;

    case WM_PAINT:
    {
      TPaint Paint(*this);
      TWindow_Paint(Paint);
      //bHandled = true;
      return 0;
    }
    break;
          
    case WM_ERASEBKGND: 
    {
      //bHandled = true;
      return 0;
    }
    break;  

	case WM_MENUCOMMAND:{
      ::HMENU HMenu = (::HMENU)Message.LParam;
     
      ::MENUINFO Info; 
      Info.cbSize = sizeof(::MENUINFO); 
      Info.fMask = MIM_MENUDATA;;

      ::GetMenuInfo(HMenu,&Info); 
      
	  prs::TNodeMenu *node = (prs::TNodeMenu*)Info.dwMenuData;
		
	  prs::TMessage_MenuCommand MenuMessage;
	  
	  prs::TNodeMenuItem *item = dynamic_cast<prs::TNodeMenuItem*>( &node->Items.Array.Get(Message.WParam) );
	  MenuMessage.Item = item->Id.GetValue();
	  MenuMessage.Sender = node;
	  
	  SendMessage(MenuMessage,node->Receiver);
      
	  break;
	}

    case WM_SIZE:
    {
      svl::TWindow::TWindow_WndProc(Message);  
      TSize Size(LOWORD(Message.LParam),HIWORD(Message.LParam));
      //Size.PTtoMM(GetScale());
      TWindow_AfterChangeClientSize(Size);
      //bHandled = true;
      return 0;
    }
    break;
    
    case WM_LBUTTONDBLCLK:
    {
      svl::TWindow::TWindow_WndProc(Message);
      TMouse Mouse;
      Mouse.State    = TMouse::EState_LButtonDblClick;
      Mouse.PtClient = MAKEPOINTS(Message.LParam);
      //Mouse.PtClient.PTtoMM(GetScale());

      if (Message.WParam & MK_CONTROL)
          Mouse.Shift << TShift::Ctrl;
      if (Message.WParam & MK_SHIFT)
          Mouse.Shift << TShift::Shift;
      if (Message.WParam & MK_LBUTTON)
          Mouse.Shift << TShift::Left;
      if (Message.WParam & MK_RBUTTON)
          Mouse.Shift << TShift::Right;
      if (Message.WParam & MK_MBUTTON)
          Mouse.Shift << TShift::Middle;

      TWindow_Mouse(Mouse);
      //bHandled = true;
      return 0;
    }
    break;

    case WM_LBUTTONDOWN:
    {
      svl::TWindow::TWindow_WndProc(Message);
      TMouse Mouse;
      Mouse.State    = TMouse::EState_LButtonDown;
      Mouse.PtClient = MAKEPOINTS(Message.LParam);
      //Mouse.PtClient.PTtoMM(GetScale());

      if (Message.WParam & MK_CONTROL)
          Mouse.Shift << TShift::Ctrl;
      if (Message.WParam & MK_SHIFT)
          Mouse.Shift << TShift::Shift;
      if (Message.WParam & MK_LBUTTON)
          Mouse.Shift << TShift::Left;
      if (Message.WParam & MK_RBUTTON)
          Mouse.Shift << TShift::Right;
      if (Message.WParam & MK_MBUTTON)
          Mouse.Shift << TShift::Middle;

      TWindow_Mouse(Mouse);
      //bHandled = true;
      return 0;
    }
    break;

    case WM_LBUTTONUP:
    {
      svl::TWindow::TWindow_WndProc(Message);
      TMouse Mouse;
      Mouse.State    = TMouse::EState_LButtonUp;
      Mouse.PtClient = MAKEPOINTS(Message.LParam);
      //Mouse.PtClient.PTtoMM(GetScale());

      if (Message.WParam & MK_CONTROL)
          Mouse.Shift << TShift::Ctrl;
      if (Message.WParam & MK_SHIFT)
          Mouse.Shift << TShift::Shift;
      if (Message.WParam & MK_LBUTTON)
          Mouse.Shift << TShift::Left;
      if (Message.WParam & MK_RBUTTON)
          Mouse.Shift << TShift::Right;
      if (Message.WParam & MK_MBUTTON)
          Mouse.Shift << TShift::Middle;

      TWindow_Mouse(Mouse);
      //bHandled = true;
      return 0;
    }
    break;

    case WM_RBUTTONDOWN:
    {
      svl::TWindow::TWindow_WndProc(Message);
      TMouse Mouse;
      Mouse.State    = TMouse::EState_RButtonDown;
      Mouse.PtClient = MAKEPOINTS(Message.LParam);
      //Mouse.PtClient.PTtoMM(GetScale());

      if (Message.WParam & MK_CONTROL)
          Mouse.Shift << TShift::Ctrl;
      if (Message.WParam & MK_SHIFT)
          Mouse.Shift << TShift::Shift;
      if (Message.WParam & MK_LBUTTON)
          Mouse.Shift << TShift::Left;
      if (Message.WParam & MK_RBUTTON)
          Mouse.Shift << TShift::Right;
      if (Message.WParam & MK_MBUTTON)
          Mouse.Shift << TShift::Middle;

      TWindow_Mouse(Mouse);
      //bHandled = true;
      return 0;
    }
    break;

    case WM_RBUTTONUP:
    {
      svl::TWindow::TWindow_WndProc(Message);
      TMouse Mouse;
      Mouse.State    = TMouse::EState_RButtonUp;
      Mouse.PtClient = MAKEPOINTS(Message.LParam);
      //Mouse.PtClient.PTtoMM(GetScale());

      if (Message.WParam & MK_CONTROL)
          Mouse.Shift << TShift::Ctrl;
      if (Message.WParam & MK_SHIFT)
          Mouse.Shift << TShift::Shift;
      if (Message.WParam & MK_LBUTTON)
          Mouse.Shift << TShift::Left;
      if (Message.WParam & MK_RBUTTON)
          Mouse.Shift << TShift::Right;
      if (Message.WParam & MK_MBUTTON)
          Mouse.Shift << TShift::Middle;

      TWindow_Mouse(Mouse);
      //bHandled = true;
      return 0;
    }
    break;

    case WM_RBUTTONDBLCLK:
    {
      svl::TWindow::TWindow_WndProc(Message);
      TMouse Mouse;
      Mouse.State    = TMouse::EState_RButtonDblClick;
      Mouse.PtClient = MAKEPOINTS(Message.LParam);
      //Mouse.PtClient.PTtoMM(GetScale());

      if (Message.WParam & MK_CONTROL)
          Mouse.Shift << TShift::Ctrl;
      if (Message.WParam & MK_SHIFT)
          Mouse.Shift << TShift::Shift;
      if (Message.WParam & MK_LBUTTON)
          Mouse.Shift << TShift::Left;
      if (Message.WParam & MK_RBUTTON)
          Mouse.Shift << TShift::Right;
      if (Message.WParam & MK_MBUTTON)
          Mouse.Shift << TShift::Middle;

      TWindow_Mouse(Mouse);
      //bHandled = true;
      return 0;
    }
    break;

    case WM_ACTIVATE:
    {
      svl::TWindow::TWindow_WndProc(Message);
      TWindow_Activate( (LOWORD(Message.WParam) & WA_ACTIVE) != 0);
      //bHandled = true;
      return 0;
    }
    break;
    
    case WM_MOUSEACTIVATE:
    {
      svl::TWindow::TWindow_WndProc(Message);
      TWindow_MouseActivate(Message.WParam,Message.LParam);
      //bHandled = true;
      return 0;
    }
    break;
    
    case WM_CLOSE:
    {
      TWindow_Close();
      //bHandled = true;
    }                                             
    break;
  }

  return svl::TWindow::TWindow_WndProc(Message);  
  
  //return Igor::TWindow<ATL::CFrameWinTraits>::HandlerWindowProc(uMsg, wParam, lParam, bHandled);
}

// TWindowArray ///////////////////////////////////////////////////////////////

//
void TWindowArray::Hide()
{
  if (Count() == 0) {
    return;
  }
  
  HDWP Hdwp = ::BeginDeferWindowPos(Count());
  
  for (int N = 0; N < Count(); N++) {
    TWindow &Window = Get(N);

    if (Window.IsVisible()) {
      TRect Rect = Window.GetWindowRect();

      ::DeferWindowPos(
        Hdwp,
        Window,
        NULL,    // HWND insert after
        Rect.Left,Rect.Top,Rect.Width,Rect.Height,
        SWP_HIDEWINDOW
      );
    }
  }
  ::EndDeferWindowPos(Hdwp);

/***************************
// Move all the windows. Use DeferWindowPos for speed.
void CWinMgr::SetWindowPositions(CWnd* pWnd)
{
   int nWindows = CountWindows();
   if (m_map && pWnd && nWindows>0) {
      HDWP hdwp = ::BeginDeferWindowPos(nWindows);
      int count=0;
      for (WINRECT* wrc=m_map; !wrc->IsEnd(); wrc++) {
         if (wrc->IsWindow()) {
            ASSERT(count < nWindows);
            HWND hwndChild = ::GetDlgItem(pWnd->m_hWnd, wrc->GetID());
            if (hwndChild) {
               const CRect& rc = wrc->GetRect();
               ::DeferWindowPos(hdwp,
                  hwndChild,
                  NULL,    // HWND insert after
                  rc.left,rc.top,rc.Width(),rc.Height(),
                  SWP_NOZORDER);
               InvalidateRect(hwndChild,NULL,TRUE); // repaint
               count++;
            }
         } else {
            // not a window: still need to repaint background
            pWnd->InvalidateRect(&wrc->GetRect());
         }
      }
      ::EndDeferWindowPos(hdwp);
   }
}
*********************************/

}
